/**
 * 线程与进程示例程序
 * fork子进程只会复制调用fork的执行线程，并不会复制父进程其他子线程。子进程自动继承父进程中互斥锁（条件变量/信号量）的状态。父进程中已经加锁的互斥锁，子进程也会被锁住
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

pthread_mutex_t mutex;

/* 父进程调用，会锁住父进程中的mutex*/
void *another(void *arg)
{
    printf("in child thread, lock the mutex\n");
    pthread_mutex_lock(&mutex);
    sleep(5);
    pthread_mutex_unlock(&mutex);
}

int main()
{

    pthread_mutex_init(&mutex, NULL);
    pthread_t id;
    pthread_create(&id, NULL, another, NULL);

    /* 父进程中的主线程暂停1s，以确保在执行fork前子线程已经开始运行并获得互斥量mutex */
    sleep(1);
    int pid;

    /* 由于前面已经sleep 1S，fork时互斥量mutex已经加锁，fork复制调用线程的锁状态，也是加锁的 */
    if ((pid = fork()) < 0) {
        perror("fork error");
        pthread_join(id, NULL);
        pthread_mutex_destroy(&mutex);
        return 1;
    }
    else if (pid == 0) { /* child */
        printf("i am in the child, want to get the lock\n");

        /* 子进程从父进程继承来互斥锁mutex的状态，该互斥锁处于锁住状态，这是由父进程中的子线程执行pthread_mutex_lock引起的。因此下面语句会导致子进程一直阻塞，而从逻辑上来说，虽然单独的子进程不应该是阻塞的 */
        pthread_mutex_lock(&mutex);
        printf("I cannot run to here, oop...\n");
        pthread_mutex_unlock(&mutex);
        exit(0);
    }
    else { /* parent */
        wait(NULL);
    }

    pthread_join(id, NULL);
    pthread_mutex_destroy(&mutex);

    return 0;
}

